Enable nullable in Stack, Libraries (9), and Applications projects#3732
Open
marcschier wants to merge 122 commits into
Open
Enable nullable in Stack, Libraries (9), and Applications projects#3732marcschier wants to merge 122 commits into
marcschier wants to merge 122 commits into
Conversation
- Add #nullable enable to AssemblyInfo, HttpsServiceHost, HttpsTransportListener - Make events nullable, fields/properties null! initialized - ValidateClientCertificate parameters nullable to match delegate signature - Local variables and bestPolicy declared nullable Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add #nullable enable to 50 source files - State machine files: use !. for required mandatory state properties - ConditionState/AlarmConditionState/etc: nullable annotations on backing fields - FiniteStateMachineState: nullable parameters for state/transition variables - Types files (ContentFilter/MonitoringFilter/etc): nullable result classes - Validate methods returning ServiceResult? when null=success - ToString IFormattable signature with nullable params - Timer fields and TimerCallback parameters made nullable Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add #nullable enable to ~107 of 187 source files in Opc.Ua.Types - Apply nullable annotations to interface signatures (IDecoder, IEncoder, IType) - Fix override Equals/CompareTo/IFormattable.ToString signatures - Make IDecoder.ReadString/Array methods return nullable to match implementations - IEnumeratedType.TryGetSymbol/IEncoder.WriteSwitchField use nullable out string - Fix Polyfills attributes for nullable awareness - Fix EnumValueTests for nullable IEnumeratedType signature - Fix MonitoredItem.cs for nullable EventFieldList.Message Note: ~80 complex files (BinaryEncoder, NodeState, etc.) remain to be migrated in a future commit. Project builds clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update Read/Write methods to accept string? fieldName since arrays and internal callers pass null. Update JsonEncoder/JsonDecoder implementations to match. Returns also nullable for ReadString/ ReadDataValue/ReadDiagnosticInfo to match JsonDecoder behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add #nullable enable to BuiltIn/Argument, RelativePath, Schema, etc. - Make IEncodable.IsEqual accept nullable IEncodeable - Make IEncoder Read/Write methods accept string? fieldName - Make IEncoder.WriteString/DataValue/DiagnosticInfo/Encodeable values nullable - Make IDecoder.Read* return types nullable to match implementations - Make class operator==/!= accept nullable for proper consumer use - Fix Argument operator== to use direct null check instead of EqualityComparer - Fix downstream NodeCache.cs to use 'is null' for ReferenceDescription comparison - Fix Subscription.cs to use null-forgiving on monitoredItem.RelativePath Progress: 117/187 Opc.Ua.Types files now nullable enabled. 70 complex files (Encoders, NodeState, Variant, etc.) remain. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add nullable to BuiltIn types: BrowseDescription, ViewDescription, EnumDefinition, EnumField, EnumValueType, RelativePath, RelativePathFormatter, RolePermissionType, StructureDefinition, StructureField, ReferenceDescription, RelativePathElement - Add nullable to State files: NodeStateFactory - Add nullable to Utils files: ServiceMessageContext, ServiceResultException, etc. - Add nullable to Encoders: EncodableObject, Enumeration - Make DataValue operator==/!= accept nullable - Replace EqualityComparer<T>.Default.Equals with manual null check in operators - Fix downstream callers in Stack/Opc.Ua and Encoders/JsonDecoder.cs Remaining: 54 complex files (BinaryEncoder, BinaryDecoder, NodeState, Variant, etc.) require deeper changes and have ~2700 errors to address. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add #nullable enable to ~49 files in Opc.Ua.Core that build clean - Apply bulk fixes: ToString IFormattable signatures, Equals object override - Make encoder Read/Write methods accept string? fieldName - Make class operator==/!= accept nullable for class types - Replace EqualityComparer<T>.Default.Equals in operators with manual null check - Fix ClientBase.MessageContext to use null-forgiving (! operator) - Fix TraceLoggerProvider to handle nullable Exception parameter - Fix Session.cs and HttpsTransportListener.cs downstream callers Remaining: 81 complex files in Opc.Ua.Core (TcpTransportListener, ApplicationConfiguration, DirectoryCertificateStore, etc.) still require deeper migration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ClientBase.Endpoint, EndpointConfiguration, NullableTransportChannel: Use ! to match IClientBase interface (non-nullable returns). The properties throw ServiceResultException if the channel is in a bad state, otherwise consumers can rely on non-null returns. Also adds #nullable enable to IClientBase.cs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add #nullable enable directive - Update method signatures to match IEncoder (string? fieldName) - Make m_namespaceMappings and m_serverMappings nullable fields - Use null-forgiving for generic WriteEncodeable internal calls - Make CloseAndReturnBuffer return byte[]? - Throw InvalidOperationException in CloseAndReturnText if not MemoryStream - WriteSwitchField fieldName is out string? per interface Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Stack/Opc.Ua.Types/State/ISystemContext.cs - Stack/Opc.Ua.Types/State/NodeBrowser.cs - Stack/Opc.Ua.Types/State/BaseDataVariableState.cs - Stack/Opc.Ua.Types/State/BaseObjectState.cs - Stack/Opc.Ua.Types/State/DataTypeState.cs - Stack/Opc.Ua.Types/Nodes/IOperationContext.cs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Stack/Opc.Ua.Types/State/BaseTypeState.cs - Stack/Opc.Ua.Types/State/ReferenceTypeState.cs - Stack/Opc.Ua.Types/State/ViewState.cs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add #nullable enable directive - Update method signatures to match IDecoder (string? fieldName) - Make m_namespaceMappings and m_serverMappings nullable fields - Make ReadString return string? to match interface - Make ReadDataValue and ReadDiagnosticInfo return nullable types - Update ReadStringArray, ReadDataValueArray, ReadDiagnosticInfoArray to return ArrayOf<T?> - Use null-forgiving for generic ReadEncodeable internal calls - Suppress CS8620 for Variant.From with nullable element ArrayOf - Make CallerMemberName functionName parameters nullable Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add #nullable enable directive - Update method signatures to match IEncoder (string? fieldName) - Make m_root, m_destination, m_namespaceMappings, m_serverMappings nullable - BeginField helper now accepts string? fieldName - WriteString, WriteDataValue, WriteDiagnosticInfo accept nullable values - Throw InvalidOperationException in CloseAndReturnText if no destination - WriteSwitchField fieldName is out string? per interface Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Utils/CoreUtils.cs
- Utils/NamespaceTable.cs
- Utils/ServiceResult.cs
- Utils/Buffers/ArrayPoolBufferWriter{T}.cs
- Utils/FileSystem/VirtualFileSystem.cs
- BuiltIn/AmbientMessageContext.cs
- BuiltIn/EnumHelper.cs
- BuiltIn/ITranslatableObject.cs
Plus minor downstream fixes for nullability of ServiceResult properties
and EnumHelper return types in EnumValue.cs, EncodeableFactory.cs, and
ServiceResultException.cs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add #nullable enable directive - Update method signatures to match IDecoder (string? fieldName) - Make m_namespaceMappings, m_serverMappings nullable - Make ReadString return string? to match interface - Make ReadDataValue and ReadDiagnosticInfo return nullable types - Update ReadStringArray, ReadDataValueArray, ReadDiagnosticInfoArray return types - Make Peek return XmlQualifiedName? - Suppress CS8620 for Variant.From with nullable element ArrayOf - Make CallerMemberName functionName parameters nullable - Update CreateBadDecodingError and SafeXmlConvert to accept nullable parameters Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Annotates DataValue, ExtensionObject, Matrix, DataContractSurrogates, and EqualityComparers with nullable reference types. Updates the corresponding Equals overloads, IFormattable.ToString signatures, IEquatable<T> contracts, IEqualityComparer<T> contracts, and operator == / != to use nullable parameters where the runtime can be null. Also fixes a downstream consumer in EncodableObject.cs that calls TryGetEncodeable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add #nullable enable directive - Update method signatures to match IDecoder (string? fieldName) - Make m_namespaceMappings, m_serverMappings nullable - Make ReadString return string? to match interface - Make ReadDataValue and ReadDiagnosticInfo return nullable types - Update ReadStringArray, ReadDataValueArray, ReadDiagnosticInfoArray return types - Make Peek return XmlQualifiedName? - Make ElementContext.Element nullable - Suppress CS8620 for Variant.From with nullable element ArrayOf/MatrixOf - Make CallerMemberName functionName parameters nullable - Update CreateBadDecodingError and SafeXmlConvert to accept nullable parameters - Use null-forgiving for TypeInfo.GetXmlName results Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- UANodeSet.cs: add nullable annotations to auto-generated XML serialization classes - UANodeSetHelpers.cs: enable nullable, update method signatures for nullable inputs - BinarySchemaValidator.cs: enable nullable, accept nullable string params - OPCBinarySchema.cs: add nullable annotations to auto-generated XML schema classes - SchemaValidator.cs: enable nullable, accept nullable params for Load and Exception helpers - TypeDictionaryValidator.cs: enable nullable, handle nullable schema properties - UA Type Dictionary.cs: add nullable annotations to auto-generated XML classes - XmlSchemaValidator.cs: enable nullable, accept nullable typeName/file params - XmlSchemaValidator2.cs: enable nullable, accept nullable typeName/file params Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…StateCollection.cs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use null-forgiving for xml after string.IsNullOrEmpty checks (older targets) - Use default! for EqualityComparer<T>.Default.Equals in BinaryEncoder - Use null-forgiving for TypeInfo.GetXmlName results - Add null coalescing for fieldName in error messages - Suppress CS8604 for Variant.From with nullable DataValue Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After enabling #nullable on 52 files in Stack/Opc.Ua.Types, downstream projects had build errors due to stricter nullability annotations flowing through interfaces. This commit fixes those errors so the full solution builds cleanly. Stack/Opc.Ua.Types fixes: - JsonDecoder.cs: nullable string handling in namespace/server URI loops, suppression of generic variance for Variant.From overloads taking ArrayOf/MatrixOf with nullable elements - JsonEncoder.cs: nullable handling for TryGetEncodeable/TryGetAsJson/ SymbolicId - BuiltInType.Obsolete.cs, QualifiedName.cs, RelativePathFormatter.cs, ReferenceDescription.cs, BaseInstanceState.cs: standard nullable annotation/suppression patterns Stack/Opc.Ua, Stack/Opc.Ua.Core fixes: - ContentFilter.cs, MonitoringFilter.cs, NotificationMessage.cs, AlarmConditionState.cs, DialogConditionState.cs, AuditEventState.cs, FiniteStateMachineState.cs, HistoryReadValueId.cs, ReadValueId.cs, WriteValue.cs: nullable annotations for INode?, out parameters from TryGetEncodeable, NumericRange.Parse non-null arguments - ClientBase.cs, ServiceResultExtensions.cs, SecuredApplicationEncoding.cs: matching nullable annotations Libraries/Opc.Ua.Client fixes: - ComplexTypeSystem.cs, DataTypeDefinitionExtension.cs, NodeCache.cs, NodeCacheContext.cs, Session.cs, SessionClientBatched.cs, SessionClientExtensions.cs, SessionConfiguration.cs, Browser.cs, MonitoredItemStatus.cs, Subscription.cs: same patterns Applications/McpServer fixes: - OpcUaJsonHelper.cs, AttributeServiceTools.cs, ConvenienceTools.cs, NodeSetExportTools.cs: same patterns Tests fixes: - EnumHelperTests.cs, ServiceResultTests.cs, ClientBaseTests.cs: match new nullable signatures Source generator fix: - ObjectTypeProxyTemplates.cs: emit pragma to suppress CS8600 in generated TryGetStructure call sites where the analyzer ignores MaybeNullWhen(false) annotations Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After enabling nullable on Opc.Ua.Server, two override-vs-base contracts became incompatible and surfaced in the Opc.Ua.Gds.Server.Common build: - CS8764 ApplicationsNodeManager.ValidateNode return type: override declares `NodeState?` but base `CustomNodeManager.ValidateNode` declared `NodeState`. Both base and override actually return null on cache miss (base line ~1857: `return handle.Node` where Node may be null; override line ~1791: `return null` when handle is null). Fixed by widening the base return type to `NodeState?` and converting the ~17 same-file `NodeState source = ValidateNode(...)` callers to `NodeState? source` (each caller already had an `if (source == null)` guard immediately after, so flow analysis narrows back to non-null with no behavior change). - CS8765 GlobalDiscoverySampleServer.ValidateRequestAsync parameter: override declared `RequestHeader requestHeader` but base `StandardServer.ValidateRequestAsync` declared `[NotNull] RequestHeader?`. Fixed by matching the base signature in the override (added `using System.Diagnostics.CodeAnalysis`). No runtime behavior change; only annotations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After enabling nullable end-to-end, several downstream errors surfaced: - MonitoredItem ctor (Opc.Ua.Server): widened originalFilter, filterToUse, range parameters to nullable. The ctor body already handled null for these (Filter/m_filterToUse fields are nullable; range null-checked at line 141; originalFilter is-pattern at 117). MemoryBufferMonitoredItem and other derived-class ctor calls now compile cleanly. - DataChangeMonitoredItem.OnReportValueChange: added ! to value/error arguments passed to MonitoredItem.ValueChanged (static method has non-null params; the surrounding code already checks if value != null on the immediately-following line so the call path is non-null in practice). Same for m_queue?.QueueValue(value!, error!). - TestDataNodeManager/AlarmNodeManager: NodeState source = ValidateNode(...) -> NodeState? source (CustomNodeManager.ValidateNode now returns NodeState? after the prior commit; downstream callers in Quickstarts.Servers needed the same change as the Opc.Ua.Server callers). - TestDataNodeManager:207: conditionsFolder!.AddNotifier(...) — the FindPredefinedNode<NodeState> returns nullable; current behavior NREs on null, ! preserves that runtime behavior while satisfying the compiler. - MemoryBufferMonitoredItem.Modify: ! on ModifyAttributes return — the base method now returns ServiceResult? (nullable) but Modify declares ServiceResult; preserves prior behavior (was returning a non-null result from a nullable signature already). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eMonitoredItem After widening m_filterToUse to nullable in commit cc8943d, two diagnostic-helper call sites (ServerUtils.ReportCreateMonitoredItem in both ctors) flagged CS8604 because the helper expects non-null filter. Same pattern used at lines 729 and 817 in commit 7e2f415 - add ! preserves the prior runtime behavior (the diagnostic helper handles null at runtime; the static signature is overly strict). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The test project links Applications/ConsoleReferenceClient/ClientSamples.cs as a Compile-Item (line 30 of csproj). After enabling nullable on ConsoleReferenceClient (commit a4d9487), the linked file gained ? annotations that fail with CS8632 in the test project's compile context. Setting <Nullable>annotations</Nullable> enables annotation PARSING without enforcing nullable analysis on the rest of the test code — minimal change that resolves the CS8632 errors without requiring a full Tests/ migration (which is out of scope for this PR). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CI test failures showed the server failing to start with InvalidOperationException in ServerSystemContext.get_OperationContext, called via Copy from DiagnosticsNodeManager.CreateAddressSpaceAsync. Commit a4d9487 changed the getter from null-silent return (with a meaningless !) to throw. This was a runtime behavior change: callers were already handling null returns (CustomNodeManager.cs:3252 has 'OperationContext != null' guard). Throwing breaks startup because DiagnosticsNodeManager runs before any operation has been issued and Copy propagates null via line 172. Restored original null-returning behavior; now declares return type as OperationContext? to match reality. All current call sites already handle null. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e revert Reverting OperationContext getter to nullable (commit 1d9df71) cascaded 8 new CS8604 errors at sites that pass it to non-null param contracts. All are in 'normal operation' code paths (after session/operation has begun) where OperationContext is invariably non-null in practice; preserved with !. Fixed sites: - DiagnosticsNodeManager.cs:316 (ResendData),:495 (ConditionRefresh),:513 (ConditionRefresh2) - MonitoredNode.cs:262 (capture from serverSystemContextToUse), :355 (cachedEntry.Context) - SamplingGroupMonitoredItemManager.cs:95 (CreateMonitoredItem),:195 (ModifyMonitoredItem) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove unresolved 'ISystemContext.OperationContext' cref in XML doc remark that prevented Opc.Ua.Server from building (the type lives in Opc.Ua, not Opc.Ua.Server, and the simple cref form failed to resolve). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… nullable Add ! after .OperationContext (now nullable). The Quickstarts SampleNodeManager diagnostic-info path here does not pre-check OperationContext for null (unlike CustomNodeManager.cs:3252 which does); preserved prior runtime behavior with !. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The ComponentCache lookup had inverted TryGetValue checks that caused
NRE on first cache hit and silently returned null after AddNodeToComponentCache:
if (!m_componentCache.TryGetValue(handle.RootId, out entry)) // BUG: when NOT found
{
return entry!.Entry!.FindChildBySymbolicName(...); // entry is null here
}
The ! inversions look like collateral damage from the bulk Server migration
script (commit 245e92b) that flipped many == to != in nullable-related
guards; later cleanup (1988bca, 1581531) caught most but missed these.
Matches the AddNodeToComponentCache pattern (which uses positive TryGetValue).
Fixes test failures: TestComponentCacheAsync, AddNodeToComponentCacheFirstAddCreatesEntry,
AddNodeToComponentCacheSecondAddIncrementsRefCountAndReturnsCachedNode,
AddNodeToComponentCacheWithComponentPath* and others. Also explains the
downstream Server startup InvalidOperationException seen in earlier CI runs
because AsyncCustomNodeManager.DeleteNodeAsync indirectly walked the cache.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…NodeInComponentCache (matches commit deb49de fix)
…FindMethodInTypeHierarchy 1. MasterNodeManager.ValidateRolePermissions: lines 3955/3960 had inverted IsEmpty checks. Comments inside the branches said 'there were no role permissions defined for this node' but the conditions were checking '!IsEmpty'. Removed the ! so the logic matches the comments. Fixes: ValidateRolePermissions_DefaultPermissions_ReturnsGood (and 4 sibling tests). 2. CustomNodeManager.cs:3148, AsyncCustomNodeManager.cs:3302: the per-spec ObjectType-method resolution path declared a NEW local 'MethodState? method2 = FindMethodInTypeHierarchy(...)' instead of assigning to the outer 'method' variable that the next 'if (method == null)' check uses. The result of the type-hierarchy lookup was discarded, so any method call on an Object instance whose method lives on its ObjectType returned BadMethodInvalid. Fixes: CallAsync_InvokesMethodFromObjectTypeAsync, CallAsync_InvokesMethodFromSuperTypeOfObjectTypeAsync. Both bugs were collateral damage from the bulk Server migration script (245e92b) and not caught by the prior cleanup commits (1988bca / 1581531). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sites only flagged in the Release build / net472 (not Debug/net10.0): - MasterNodeManager.cs:1716: context.Session is nullable; ! at use site. - ConsoleReferenceSubscriber/Program.cs:249,255,282,292,298: dataSet.Fields, dataSet, and DataSetMetaData are nullable per Opc.Ua.PubSub migration. Added ! at deref sites (sample-app code path is exercised only with real metadata messages). - ConsoleReferencePublisher/PublishedValuesWrites.cs:352,356: IUaPubSubDataStore.ReadPublishedDataItem now returns DataValue? (key-not-found path); changed local to DataValue? and added explicit null check before dereferencing WrappedValue. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The line was 'context.Session!.SaveContinuationPoint(currentCp);' but 'context' itself is nullable in this method (other use sites at lines 1665, 1686 use 'context!'). The ! after Session doesn't help when context.* is the first deref. Added ! after context too. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Documents the ~3,810 ! operators remaining after the nullable migration, clustered into 15 root-cause groups with removal strategies, effort estimates, and a 6-PR follow-up roadmap. Also flags 2 latent (expr as T)! bug candidates in Opc.Ua.PubSub/Encoding/PubSubJsonDecoder.cs:928,1293. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace 15 `= null!;` initializers on auto-properties in PubSub EventArgs and DTO classes with the C# 11 `required` modifier. The repo's Stack/Opc.Ua.Types already provides PolySharp-generated RequiredMemberAttribute polyfills for older TFMs (net472/48/standard2.1) so this works across all 6 target frameworks without adding new compat code. Modified EventArgs (1 prop each): ConnectionEventArgs, DataSetReaderEventArgs, DataSetWriterEventArgs, ExtensionFieldEventArgs, PubSubStateChangedEventArgs, PublishedDataSetEventArgs, ReaderGroupEventArgs, WriterGroupEventArgs Multi-property classes converted: ConfigurationUpdatingEventArgs (Parent, NewValue) RawDataReceivedEventArgs (Message, Source, PubSubConnectionConfiguration) DataSetWriterConfigurationResponse (DataSetWriterIds, StatusCodes; DataSetWriterConfig left as null! since it is conditionally set) Caller fix: UaPubSubConnection.GetDataSetWriterDiscoveryResponses refactored from post-construction property assignment to object-initializer syntax to satisfy the required-property contract; preserved the conditional DataSetWriterConfig=null on not-found path (no runtime change). Test updates: 5 tests updated to provide initializers for now-required properties (Message=[], Source=string.Empty, etc.). Skipped: EventArgs whose properties have `internal set;` (populated by framework code, not callers) — keeping `= null!;` is correct there. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Server Added 10 [MemberNotNull] attributes across 5 files documenting which late-init fields each lifecycle method populates. The compiler now verifies these methods set the fields, eliminating the need for ! operators at downstream use sites. ServerInternalData.cs (9 attributes, 21 member refs): SetNodeManager, SetMainNodeManagerFactory, CreateServerObjectAsync, SetSessionManager, SetMonitoredItemQueueFactory, SetSubscriptionStore, SetAggregateManager, SetModellingRulesManager Session.UpdateUserIdentity (1 attribute, 2 member refs): EffectiveIdentity, IdentityToken Use-site eliminations (5 ! removed): CustomNodeManager.cs:4972 Server!.NodeManager! -> Server.NodeManager AsyncCustomNodeManager.cs:5162 same pattern StandardServer.cs:3700 ServerInternal.ServerObject! -> .ServerObject The = null!; initializers were preserved because constructors do not call the lifecycle methods (compiler still requires the suppressor); the attributes formally document the contract that flow analysis can use inside any caller that has invoked the lifecycle method. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…g fixes
A) Two latent (expr as T)! cast bug fixes in PubSubJsonDecoder.cs:
- Line 928: (serverUriToken as string)! -> (string)serverUriToken (clean
InvalidCastException instead of swallowed-then-NRE in ToServerIndex).
- Line 1293: (array.Value as Array)! -> 'is not Array arrayValue' pattern
match with descriptive ServiceResultException(BadDecodingError).
B) ArraySegmentExtensions.GetArray() helper + bulk migration:
New internal extension Stack/Opc.Ua.Core/Utils/ArraySegmentExtensions.cs
with Debug.Assert + AggressiveInlining. Replaced 61 sites of
ArraySegment.Array! with .GetArray() across 9 files in Opc.Ua.Core
(BufferManager, ArraySegmentStream, CryptoUtils, EncryptedSecret,
RsaUtils, UaSCBinaryChannel + Asymmetric/Rsa/Symmetric).
C) ToArray()!.Cast<T> -> .ToList().OfType<T> in JsonDecoder.cs at lines
3937 and 3941 (NamespaceTable/StringTable construction). ToList yields
non-null List<string?>, OfType filters nulls and yields IEnumerable<string>
matching the consumer signature.
Total: ~68 ! operators eliminated, 2 latent bugs fixed.
Build: Opc.Ua.Core, Opc.Ua.PubSub, Opc.Ua.Types all succeed (0 warnings).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Part A (Dispose-time field cleanup): Only Nonce.cs.m_ecdh qualified for safe conversion (already declared ECDiffieHellman?; just changed Dispose-line null! to null). All other candidate sites (BinaryEncoder/Decoder, XmlDecoder, PubSubJson*, BaseComplexType, MonitoredItem, PooledBuffer, ArraySegmentStream, TcpTransportListener) were rejected by the conservative criteria because their fields are widely accessed without null checks; making them nullable would require new null guards (a runtime behavior change). Part B (Type.GetElementType()! pattern replacement): 15 sites converted from .GetElementType()! to either 'is Type x' pattern matching (compile-time non-null narrowing, no exception path) or '?? throw InvalidOperationException' for assignment cases. Files (sites): Stack/Opc.Ua.Types/BuiltIn/EnumValue.cs (2) Stack/Opc.Ua.Types/BuiltIn/TypeInfo.cs (3) Stack/Opc.Ua.Types/BuiltIn/VariantHelper.cs (1) Stack/Opc.Ua.Types/BuiltIn/Matrix.cs (3) Libraries/Opc.Ua.Client.ComplexTypes/Types/ComplexTypePropertyInfo.cs (3) Libraries/Opc.Ua.PubSub/Encoding/PubSubJsonEncoder.cs (3) Total: 16 ! operators eliminated. Builds clean (Types/Core/PubSub all 0 warnings; pre-existing baseline errors in MonitoredNode/SessionExtensions unrelated to this change). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Make `string fieldName` parameter nullable across all encoder/decoder APIs. In binary encoding fieldName is unused (positional encoding) and callers were universally passing `null!`; making the parameter nullable eliminates the ! at every call site. Interface changes (10 methods each): IEncoder.cs: WriteEncodeable*, WriteEnumerated*, WriteEncodeableArray*, WriteEncodeableArrayAsExtensionObjects, WriteEncodeableMatrix* IDecoder.cs: ReadEncodeable*, ReadEnumerated*, ReadEncodeableArray*, ReadEncodeableMatrix, ReadEncodeableArrayAsExtensionObjects, ReadVariantValue Implementations updated: BinaryEncoder/Decoder, XmlEncoder/Decoder, XmlParser (private helper), JsonEncoder/Decoder — 72 method signatures total. AuditEvent.Initialize source parameter: BaseEventState.Initialize and AuditEventState.Initialize: NodeState source -> NodeState? source. Eliminates ! at 25 call sites in AuditEvents.cs (×17+3), Subscription.cs (×2), MonitoredItem.cs, CustomNodeManager.cs (×3). Call-site replacements (88 total): - 63 IEncoder/IDecoder null! -> null sites - 25 e.Initialize(ctx, null!, ...) -> e.Initialize(ctx, null, ...) Source-breaking note: The interface ? annotations on fieldName are source-breaking for downstream consumers with NRT enabled — they will see new warnings when overriding/implementing the interfaces. Binary-compatible. Builds: Types/Core/PubSub all 0 warnings. Server/Client have only the pre-existing `unions` baseline errors (verified via git stash). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
# Conflicts: # Libraries/Opc.Ua.Client/Browser.cs # Libraries/Opc.Ua.Client/ComplexTypes/NodeCacheResolver.cs # Libraries/Opc.Ua.Client/NodeCache/LruNodeCache.cs # Libraries/Opc.Ua.Client/NodeCache/NodeCache.cs # Libraries/Opc.Ua.Client/NodeCache/NodeCacheObsolete.cs # Libraries/Opc.Ua.Client/Session/DefaultSessionFactory.cs # Libraries/Opc.Ua.Client/Session/Session.cs # Libraries/Opc.Ua.Client/Session/SessionObsolete.cs # Libraries/Opc.Ua.Client/Subscription/MonitoredItem.cs # Libraries/Opc.Ua.Client/Subscription/Subscription.cs # Libraries/Opc.Ua.Server/Fluent/NodeManagerBuilder.cs # Stack/Opc.Ua.Core/Security/Constants/AdditionalParameterNames.cs # Stack/Opc.Ua.Core/Security/Constants/SecurityPolicies.cs # Stack/Opc.Ua.Core/Security/Constants/SecurityPolicyInfo.cs # Stack/Opc.Ua.Core/Stack/Client/DiscoveryClient.cs # Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs # Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Asymmetric.cs # Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Rsa.cs # Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Symmetric.cs # Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryClientChannel.cs # Stack/Opc.Ua.Core/Stack/Transport/NullChannel.cs # Stack/Opc.Ua.Core/Stack/Types/X509IdentityTokenHandler.cs # Stack/Opc.Ua.Types/BuiltIn/DataContractSurrogates.cs # Stack/Opc.Ua.Types/BuiltIn/ExtensionObject.cs # Stack/Opc.Ua.Types/BuiltIn/Variant.cs
After merging master (PR #3730), 3 test sites still passed null as the first arg to the 2-arg ConfiguredEndpoint(ConfiguredEndpointCollection, EndpointDescription) ctor whose collection param is non-nullable. The 3-arg overload with nullable collection was already used in production code (DefaultServerRedundancyHandler, ManagedSessionBuilder); apply the same pattern in tests by adding 'configuration: null' to disambiguate to the 3-arg overload. Files: Tests/Opc.Ua.Client.Tests/ClientBuilder/ManagedSessionBuilderTests.cs:54 Tests/Opc.Ua.Client.Tests/ClientBuilder/OpcUaClientServiceCollectionExtensionsTests.cs:44 Tests/Opc.Ua.Client.Tests/Session/ServerRedundancyHandlerTests.cs:375 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After the master merge (Certificate Manager PR #3688) re-introduced existing test files that pass null to APIs in Opc.Ua.Types which the nullable migration had not yet annotated. The APIs already handle null internally (via if-null guards or throw); just need the parameter annotation to match the existing runtime contract. Widened params (all already null-tolerant): - EnumHelper.EnumArrayToInt32Array(Array values) -> (Array? values) - EnumHelper.EnumArrayToInt32Matrix(Array values) -> (Array? values) - RelativePath.IsEmpty(RelativePath relativePath) -> (RelativePath? relativePath) - RelativePath.Parse(string, ITypeTable typeTree) -> (string, ITypeTable? typeTree) - RelativePath.Parse(string, ITypeTable, NamespaceTable, NamespaceTable) -> (string, ITypeTable?, NamespaceTable, NamespaceTable) - ServiceResultException.Create(StatusCode, string format, params) -> (StatusCode, string? format, params) - ServiceResultException.Create(StatusCode, Exception, string format, params) -> (StatusCode, Exception, string? format, params) Fixes 8 CS8625 errors in Tests/Opc.Ua.Types.Tests that cascade-cancelled ~20 dependent test jobs. No runtime behavior change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split the long inline justification comment off the #pragma warning disable line so the line stays within the 120-char limit enforced by Roslynator's RCS0056 analyzer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After the certificate-manager refactor merge, these sites needed nullable annotations to align with the new Certificate / CertificateManager API surface: ApplicationInstance.cs: - ctor: NullLogger fallback when telemetry parameter is null (CS8600) - CertificateManager property declared nullable (CS8618) - ApplicationConfiguration!.CertificateManager (CS8602; never null after ctor) - localManager: CertificateManager? (CS8600 in Dispose) - CertificateManager!.ValidateAsync (CS8602; checked just above) - m_telemetry! when passing to CertificateManagerFactory.Create - passwordProvider declared as ICertificatePasswordProvider? at both sites - id.SubjectName! in format args (CS8604) ApplicationConfigurationBuilder.cs: - ApplicationConfiguration.ServerConfiguration! (CS8602; non-null in this builder) HttpsTransportListener.cs: - serverCertificate!.AsX509Certificate2() (CS8602) - clientCertificate!.RawData (CS8602; param is nullable but sslPolicyErrors=None guard above) No runtime behavior change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After the master merge of PR #3688 (Certificate manager refactor), GDS code paths weren't fully aligned with the new ref-counted Certificate type and CertificateManager API. Fixes by file: ICertificateGroup.cs: Dictionary<NodeId, Certificate?> (was non-null; matches what implementations actually populate). CertificateGroup.cs: CertificateIssuer property nullable (CS8618 x2); fixed dictionary creation X509Certificate2? -> Certificate?; telemetry! in OpenStore (provably non-null per surrounding flow). ApplicationsNodeManager.cs: TrustListManager property nullable (CS8618). GlobalDiscoverySampleServer.cs: removed obsolete tempIdentity?.Dispose() scaffolding (UserIdentity no longer IDisposable post-merge) at lines 249 and 434 (CS1061 x2); CertificateManager! and userCertificate! derefs matching the StandardServer pattern. GlobalDiscoveryServerClient.cs: localLds declared nullable to allow conditional null assignment (CS8600 x2); lds! after ??= with comment. ServerPushConfigurationClient.cs: m_serverConfiguration! matching surrounding pattern. Tests/.../CertificateStoreTypeTest.cs (2 files): aligned LoadPrivateKeyAsync param nullability with ICertificateStore signature (CS8767 x4); added ! for nullable trust-list args (CS8604 x2). No runtime behavior change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… merge After the master merge, Quickstarts.Servers code paths needed nullable annotations to align with the new Certificate API and master's nullable property declarations: MemoryBufferBrowser.cs (lines 140-164): - BrowseName.Name typed string?, added ! at use sites - m_buffer is nullable in this context, added ! at use sites - SizeInBytes is BaseDataVariableState<uint>?, added ! before .Value ReferenceServer.cs: - referenceNodeManager local typed ReferenceNodeManager? (was non-null but assigned null on success path; CS8600) - Inherited CertificateManager property is nullable; added ! at deref - userCertificate parameter is Certificate?; added ! when passing to ValidateAsync (the caller path's null check is implicit) TestDataNodeManager.cs:556: - details parameter is ReadRawModifiedDetails?; added ! when passing to HistoryDataReader.BeginReadRaw (the path is reached only when details is non-null per the method's outer null check) No runtime behavior change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ParseExtension<T> returns T?; declare gdsConfig as nullable to match. The subsequent 'if (gdsConfig != null)' guard already handles null. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed changes
Enable C# nullable reference types across all production code projects in the OPC UA stack — Stack/, Libraries/, and Applications/ — applying systematic annotations and minimizing
!(null-forgiving) operators per themigrate-nullable-referencesskill conventions.Scope
Nullable-enabled projects (21 total):
Stack/(4):Opc.Ua.Bindings.Https,Opc.Ua,Opc.Ua.Types,Opc.Ua.CoreLibraries/(9):Opc.Ua.Security.Certificates,Opc.Ua.Configuration,Opc.Ua.Client,Opc.Ua.Client.ComplexTypes,Opc.Ua.Server,Opc.Ua.PubSub,Opc.Ua.Gds.Common,Opc.Ua.Gds.Client.Common,Opc.Ua.Gds.Server.CommonApplications/(8):ConsoleReferenceServer,ConsoleReferenceClient,ConsoleReferencePublisher,ConsoleReferenceSubscriber,MinimalBoilerServer,McpServer,Quickstarts.Serversand the Mono variantTests/projects are intentionally out of scope for this PR.Conventions applied
<Nullable>enable</Nullable>set at project level (no per-file#nullable enabledirectives)[NotNullWhen],[MemberNotNull],[NotNullIfNotNull],[MaybeNullWhen]attributes used where simple?cannot express the contract= null!for late-init fields (paired with[MemberNotNull]on initializer methods)!operators reduced across multiple cleanup passes!justified by upstream invariants or commentsLatent bugs surfaced and fixed
During the audit, ~25 latent null-deref risks and dead-code paths were flagged with TODOs and then fixed in dedicated commits. Examples:
EndpointDescription.SecurityPolicyUri = null!→ useSecurityPolicies.NoneliteralContentFilter.Result/ElementResult(null!)→ useServiceResult.Good(expr as Type)!patterns (13 sites) replaced withis-pattern early-return + log warningBatchPersistor.DeleteBatchhad inverted regex predicate (deleted wrong batches)AlarmConditionTypeHolder.SetValuehad unreachableelse if (UpdateSuppression()); first branch should have beenUpdateShelving()(matching the message body)AlarmNodeManagerhad 4 deadsourceControllers == nullchecks (the dictionary getter is non-null)Durable*MonitoredItemQueue.Restore(null)left fields in inconsistent persisted-but-empty stateConsoleReferenceClientNRE risks onNodeCache.FindAsyncandascasts in subscription notifications[NotNullWhen(true)]so callers no longer need!Master integration
Branch was merged twice with origin/master:
UnionAttributepolyfill,TryGetEncodeable→TryGetValuerename) — propagated through all consumers; nullable annotations preserved across the rename.!fixes inAuditEvents.csandStandardServer.csbecause the new code paths didn't satisfy the now-<Nullable>enable</Nullable>dOpc.Ua.Server.Types of changes
Checklist
Further comments
Source-breaking changes
Adding
?to a public method's return or parameter is metadata-only at the IL level (no behavior change), but is source-breaking for consumers who have NRT enabled — they will see new warnings/errors. Consumers who have NRT disabled will be unaffected. The annotations match the actual runtime behavior already shipping in master.Local validation note
The local SDK preview (
dotnet 10.0.300-preview.0.26177.108) fails on master's new union-pattern code paths (is { IsNull: false }on[Union]-marked types likeNodeId) due to a preview compiler issue. CI uses GA SDK 10.0.7 where these compile cleanly. Errors inMonitoredNode.csand a few related files reported only locally are pre-existing baseline noise unrelated to this PR.